package fr.cpe.dp.projet2.exemple;

/**
 * @author Kathy Sierra, Bert Bates : "Java T�te la Premi�re" Mise en forme des
 * commentaires Fran�oise PERRIN
 */

/**
 * Le programme suivant affiche des formes dans un panneau au rythme d'une
 * partition de musique qu'il a pr�alablement construite
 *
 * Pour qu�un son sorte des haut-parleurs, il faut envoyer les donn�es MIDI � un
 * �quipement MIDI, qui lit les instructions et les transforme en son, en
 * d�clenchant un instrument r�el ou un instrument � virtuel � (un programme
 * synth�tiseur).
 *
 * Il faut QUATRE composants : 1 - Celui qui joue la musique et restitue
 * r�ellement le son : le s�quenceur (le voir comme un lecteur de CD) 2 - la
 * musique � jouer : la s�quence est le morceau jou� par le s�quenceur (la voir
 * comme 1 CD) 3 - La partie de la s�quence qui contient les vraies informations
 * : une piste (la voir comme 1 morceau du CD) 4 - Les vraies informations
 * contenues dans une piste sont des �v�nements MIDI : quelles notes jouer,
 * combien de temps, etc. Un �v�nement MIDI est un message compr�hensible par le
 * s�quenceur. Il pourrait dire (s�il parlait) : � Maintenant joue un do,
 * joue-le � cette vitesse et tiens la note pendant tant de temps �. Un
 * �v�nement MIDI pourrait �galement dire par exemple : � Change l�instrument
 * courant en fl�te �.
 */
import java.awt.Color;
import java.awt.Graphics;

import javax.sound.midi.ControllerEventListener;
import javax.sound.midi.MidiEvent;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.Track;
import javax.swing.JFrame;
import javax.swing.JPanel;

// ce programme joue une musique al�atoire,et affiche des rectangles pleins, en rythme.
public class MidiExemple {
    static JFrame f = new JFrame("Mon nouveau clip vid�o");
    static MonPanneau ml;

    public static void main(String[] args) {
        MidiExemple mini = new MidiExemple();
        mini.go();
    }

    public void go() {

        installerIHM();

        /*
         * Le processus comprend 5 �tapes
         * 1 - Obtenir un s�quenceur, un objet Sequencer, et l�ouvrir
         * 2 - Cr�er un nouvel objet Sequence
         * 3 - Demander � la Sequence de cr�er une piste piste de type Track
         * 4 - Remplir la piste d��v�nements MIDI � MidiEvents � et transmettre la s�quence au s�quenceur
         * 5 - D�marrer le s�quenceur avec la m�thode start() 
         */
        try {

            // cr�er (et ouvrir) un s�quenceur
            Sequencer sequenceur = MidiSystem.getSequencer();
            sequenceur.open();

            // cr�er une s�quence et une piste
            Sequence seq = new Sequence(Sequence.PPQ, 4);
            Track piste = seq.createTrack();

            // maintenant cr�er deux �v�nements midi (contenant un message midi)
            int r = 0;
            for (int i = 0; i < 100; i += 4) {

                r = (int) ((Math.random() * 50) + 1);

				// ajouter les �v�nements � la piste
                // 144 = noteOn, 1 = piano, 44 = la note, 100 = v�locit�
                piste.add(makeEvent(144, 1, r, 100, i));

                /* Pour suivre le rythme. Nous ins�rons notre PROPRE ControllerEvent :
                 * 176 indique que le type de l'�v�nement est ControllerEvent) 
                 * avec un argument pour le num�ro d'�v�nement, 127. 
                 * Cet �v�nement ne fera RIEN ! 
                 * Il n'est l� QUE pour que nous ayons un �v�nement chaque fois qu'une note est jou�e. 
                 * Autrement dit, sa seule raison d'�tre est qu'un �v�nement se d�clenche 
                 * que NOUS puissions �couter (impossible d'�couter NOTE ON/OFF ). 
                 * Cet �v�nement a lieu sur le M�ME temps que NOTE ON. 
                 */
                piste.add(makeEvent(176, 1, 127, 0, i));

                // 128 = noteOff				
                piste.add(makeEvent(128, 1, r, 100, i + 2));

            } // fin de la boucle

            // ajouter la s�quence au s�quenceur, fixer le timing et d�marrer
            sequenceur.setSequence(seq);
            sequenceur.setTempoInBPM(120);
            sequenceur.start();

            /* le panneau de dessin (�couteur) doit s'enregistrer aupr�s du s�quenceur. 
             * La m�thode d'enregistrement accepte l'�couteur 
             * ET un tableau d'entiers repr�sentant la liste d'�v�nements voulus. 
             * Ici, nous n'en voulons qu'un, le N� 127.
             */
            sequenceur.addControllerEventListener(ml, new int[]{127});

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    } // fin de la m�thode go()

    public MidiEvent makeEvent(int comd, int can, int un, int deux, int tic) {
        MidiEvent evenement = null;
        try {
            ShortMessage a = new ShortMessage();
            a.setMessage(comd, can, un, deux);
            evenement = new MidiEvent(a, tic);

        } catch (Exception e) {
        }
        return evenement;
    }

    public void installerIHM() {
        ml = new MonPanneau();
        f.setContentPane(ml);
        f.setBounds(30, 30, 300, 300);
        f.setVisible(true);
    }


    /* le panneau de dessin va �couter les ControllerEvents
     * et donc doit impl�menter l'interface �couteur
     */
    class MonPanneau extends JPanel implements ControllerEventListener {

        // nous ne voulons d'images que si nous avons un �v�nement
        boolean msg = false;

        public void controlChange(ShortMessage evenement) {
            msg = true;
            repaint();
            
        }

        public void paintComponent(Graphics g) {
            if (msg) {
                
                int r = (int) (Math.random() * 250);
                int gr = (int) (Math.random() * 250);
                int b = (int) (Math.random() * 250);

                g.setColor(new Color(r, gr, b));

                int ht = (int) ((Math.random() * 120) + 10);
                int width = (int) ((Math.random() * 120) + 10);

                int x = (int) ((Math.random() * 40) + 10);
                int y = (int) ((Math.random() * 40) + 10);

                g.fillRect(x, y, ht, width);
                msg = false;
            }
        }
    }

}
